package ui.client;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.UnknownHostException;

import net.ClientSocket;
import util.IEventCallback;
import util.IOUtil;
import util.MessageInfo;

public class FileTransferClient implements IEventCallback {
	private String host;
	private int port;
	private JFileTransferClientApp frame;
	private ClientSocket clientSocket;
	
	private volatile boolean pauseRequested;
	private volatile boolean stopRequested;
		
	public FileTransferClient(String host, int port) { 
	    this.host = host; 
	    this.port = port; 
	} 
	
	public void setCallback(JFileTransferClientApp f)
	{
		if( frame == null)
			frame = f;
	}
	public void pauseRequest() throws Exception {
		System.out.println("[FileTransferClient] pauseRequest, current status: " + pauseRequested); 
		pauseRequested = !pauseRequested;
		this.callback(pauseRequested ? IEventCallback.EVT_CLIENT_SEND_FILE_PAUSE : IEventCallback.EVT_CLIENT_SEND_FILE_RESUME);
	}
	public void stopRequest() throws Exception {
		System.out.println("[FileTransferClient] stopRequest");
		stopRequested = true;
		this.callback(IEventCallback.EVT_CLIENT_SEND_FILE_STOP);
	}
	
	protected ClientSocket getSocket() {
		if (clientSocket == null)
		{
			clientSocket = new ClientSocket(this.host, this.port);
		}
		return clientSocket;
	}
	
	protected void closeSocket() throws Exception {
		if (clientSocket != null)
		{
			clientSocket.closeConnection();
		}
	}
	public boolean preSendSelectedFile(String srcfile, boolean autoResume) {
		ClientSocket s = this.getSocket();
		long startPos = -1;
		try{
			s.createConnection();
			if (!s.isNullSocket()) {
				File f = new File(srcfile);
				srcfile += IOUtil.DEFAULT_DELIMITER + f.length();
				System.out.println("[preSendSelectedFile] srcfile: " + srcfile);
				// Send source file information to server
	        	s.sendMessage(srcfile);
	        	// Get target file information from server
	        	String targetfile = s.getMessage();
	        	System.out.println("[preSendSelectedFile] targetfile: " + targetfile);
	        	if(!IOUtil.isNullString(targetfile))
	        	{
	        		int pos = targetfile.lastIndexOf(IOUtil.DEFAULT_DELIMITER) + 1;
	        		startPos = Long.valueOf(targetfile.substring(pos)).longValue();
	        		if(autoResume)
	        			this.callback(IEventCallback.EVT_CLIENT_TARGET_FILE_RESUME , startPos);
	        		else
	        			this.callback(IEventCallback.EVT_CLIENT_TARGET_FILE_SIZE , startPos);
	        		System.out.println("[preSendSelectedFile] startPos: " + startPos);
	        	}
			}
			
		} catch (UnknownHostException e) { 
			this.callback(e.getMessage(), IEventCallback.ERR_UNKNOWN_HOST_EXCEPTION);
        	e.printStackTrace(); 
        } catch (ConnectException e) {
        	this.callback(e.getMessage(), IEventCallback.ERR_CONNECT_EXCEPTION);
        	e.printStackTrace(); 
        } catch (IOException e) { 
        	this.callback(e.getMessage(), IEventCallback.ERR_IO_EXCEPTION);
            e.printStackTrace(); 
        } catch (Exception e) {
        	this.callback(e.getMessage(), IEventCallback.ERR_EXCEPTION);
			e.printStackTrace();
		}
		return startPos >=0 ? true: false;
	}
	
    public void sendSelectedFile(String srcfile, String command, long startPos) { 
        try {
    		pauseRequested = false;
    		stopRequested = false;
        	ClientSocket s = this.getSocket();
        	if (!s.isNullSocket())
        	{
        		s.sendMessage(command);
            	if (!command.equalsIgnoreCase(IOUtil.CMD_CANCEL))
            		startSendFile(srcfile, startPos);
            	//Close connection after EVT_CLIENT_CONN_CLOSE_READY callback
        		//s.closeConnection();
        	}
        } catch (UnknownHostException e) { 
        	this.callback(e.getMessage(), IEventCallback.ERR_UNKNOWN_HOST_EXCEPTION);
        	e.printStackTrace(); 
        } catch (IOException e) { 
        	this.callback(e.getMessage(), IEventCallback.ERR_IO_EXCEPTION);
            e.printStackTrace(); 
        } catch (Exception e) {
        	this.callback(e.getMessage(), IEventCallback.ERR_EXCEPTION);
			e.printStackTrace();
		} finally {
			
		}
        
    }

    private void startSendFile(String srcfile, long startPos)
    {
    	try{
    		ClientSocket s = this.getSocket();
    		if(!s.isNullSocket())
    		{
    			InputStream inStream = new FileInputStream(srcfile);
            	OutputStream outStream = s.getOutputStream();
            	inStream.skip(startPos);
            	
            	File f = new File(srcfile);
            	long fileLength = f.length();
            	
            	System.out.println("[FileTransferClient] startSendFile, " + srcfile + " size: " + fileLength); 
            	System.out.println("[FileTransferClient] startSendFile, copyStream start! "); 
            	this.callback(IEventCallback.EVT_CLIENT_SEND_FILE_START);
            	try{
            		byte[] buffer = new byte[IOUtil.DEFAULT_READ_BUFFER_SIZE];
        			long currentReadBytes = 0;
        			int bytesRead = -1;
        			int preProgress = 0; 
        			while ((bytesRead = inStream.read(buffer)) > -1) {
        				if(stopRequested)
        					break;
        				while(pauseRequested)
        					Thread.sleep(1000);
        				currentReadBytes += bytesRead;
        				outStream.write(buffer, 0, bytesRead);
//        				int progress = IOUtil.getProgress(currentReadBytes, fileLength);
//        				if (progress != preProgress)
//        				{
//        					//this.callback(IEventCallback.EVT_CLIENT_SEND_FILE_PROGRESS, progress);
//        					preProgress = progress;
//        					Thread.sleep(300);
//        				}
        			}
        			
            	} catch (InterruptedException e) {
        			this.callback(e.getMessage(), IEventCallback.ERR_INTERRUPTED_EXCEPTION);
        			e.printStackTrace();
        		} finally {
        			inStream.close();
        			//outStream.close();
        		}
        		this.callback(IEventCallback.EVT_CLIENT_SEND_FILE_COMPLETE);
        		System.out.println("[FileTransferClient] startSendFile, copyStream end! ");
    		}
    	} catch(SocketException e) {
    		this.callback(e.getMessage(), IEventCallback.ERR_SOCKET_EXCEPTION);        	
    		e.printStackTrace();
    	} catch (IOException e) { 
    		this.callback(e.getMessage(), IEventCallback.ERR_IO_EXCEPTION);
    		e.printStackTrace();
        } catch (Exception e) {
        	this.callback(e.getMessage(), IEventCallback.ERR_EXCEPTION);
        	e.printStackTrace();
		} 
    }
	
    public void getServerMsg() throws Exception{
    	ClientSocket s = this.getSocket();
    	while(!s.isNullSocket()) {
    		try {
    			MessageInfo msgInfo = s.getMessageInfo();
    			System.out.println("[getServerMsg] id: [" +msgInfo.getMsgType()+ "] msg: " + msgInfo.getMsg());
    			if(msgInfo.getMsgType() == IEventCallback.EVT_SERVER_RECV_FILE_START) {
    				this.callback(IEventCallback.EVT_SERVER_RECV_FILE_START);
    			}
    			else if(msgInfo.getMsgType() == IEventCallback.EVT_SERVER_RECV_FILE_PROGRESS)
    			{
    				this.callback(msgInfo.getMsgType(), Long.valueOf(msgInfo.getMsg()).longValue());
    			}
    			else if(msgInfo.getMsgType() == IEventCallback.EVT_SERVER_RECV_FILE_COMPLETE)
    			{
    				MessageInfo msg = new MessageInfo(IEventCallback.EVT_CLIENT_CONN_CLOSE_READY);
    				s.sendMessageInfo(msg);
    				break;
    			}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	this.callback(IEventCallback.EVT_CLIENT_CONN_CLOSE_READY);
    }
	public void callback(long... argv) throws Exception {
		frame.doEvtCallback(IEventCallback.CALLBACK_TYPE_CLIENT, argv);
	}
	
	public void callback(String message, long... argv) {
		frame.doErrCallback(IEventCallback.CALLBACK_TYPE_CLIENT, message, argv);
	}
	
}